
#include "core/core.h"
#include "core/extension/pluginmanager.h"

#include "xdl/symbol.h"

#include "symboleditor/document.h"
#include "symboleditor/command/setpropertycommand.h"
#include "symboleditor/command/clonecommand.h"
#include "symboleditor/command/movecommand.h"
#include "symboleditor/command/additemcommand.h"
#include "symboleditor/command/aligncommand.h"
#include "symboleditor/command/distributecommand.h"
#include "symboleditor/command/stackordercommand.h"

#include <QtTest>

using namespace SymbolEditor;

class tst_Document : public QObject
{
    Q_OBJECT
private slots:
    void initTestCase();
    void cleanupTestCase();

    void setPropertyCommand();
    void setColorPropertyCommand();
    void cloneCommand();
    void moveCommand();

    void placeCircleCommand();
    void placeCircularArcCommand();
    void placeEllipseCommand();
    void placeEllipticalArcCommand();
    void placeRectangleCommand();
    void placePolylineCommand();
    void placePolygonCommand();
    void placePinCommand();
    void placeLabelCommand();

    void alignLeftCommand();
    void alignHCenterCommand();
    void alignRightCommand();
    void alignTopCommand();
    void alignVCenterCommand();
    void alignBottomCommand();
    void alignCommandWithItemTransform();

    void distributeLeftBorders();
    void distributeHCenters();
    void distributeHGaps();
    void distributeRightBorders();
    void distributeTopBorders();
    void distributeVCenters();
    void distributeVGaps();
    void distributeBottomBorders();

    void itemAreStackedInItemCreationOrder();
    void removingItemsDoesntReshuffleStackOrder();
    void movingTopItemToTopDoesNothing();
    void stackUpSameDoesNothing();
    void stackUpWorks();
    void movingBottomItemToBottomDoesNothing();
    void stackDownSameDoesNothing();
    void stackDownWorks();

};

void tst_Document::initTestCase()
{
    SymbolEditor::registerMetaTypes();
}

void tst_Document::cleanupTestCase()
{

}

void tst_Document::setPropertyCommand()
{
    Document document;
    auto id = document.addItem(Circle);
    document.setItemProperty(id, RadiusProperty, 3.14);

    auto command = new SetPropertyCommand();
    command->setItemId(id);
    command->setPropertId(RadiusProperty);
    command->setPropertyValue(6.28);
    command->setDocument(&document);

    command->redo();
    QCOMPARE(document.itemProperty(id, RadiusProperty).toReal(), 6.28);

    command->undo();
    QCOMPARE(document.itemProperty(id, RadiusProperty).toReal(), 3.14);

    command->redo();
    QCOMPARE(document.itemProperty(id, RadiusProperty).toReal(), 6.28);
}

void tst_Document::setColorPropertyCommand()
{
    QVariant oldColor = QVariant::fromValue(Green);
    QVariant newColor = QVariant::fromValue(Red);

    Document document;
    auto id = document.addItem(Circle);
    document.setItemProperty(id, LineColorProperty, oldColor);

    auto command = new SetPropertyCommand();
    command->setItemId(id);
    command->setPropertId(LineColorProperty);
    command->setPropertyValue(newColor);
    command->setDocument(&document);

    command->redo();
    QCOMPARE(document.itemProperty(id, LineColorProperty), newColor);

    command->undo();
    QCOMPARE(document.itemProperty(id, LineColorProperty), oldColor);

    command->redo();
    QCOMPARE(document.itemProperty(id, LineColorProperty), newColor);
}

void tst_Document::cloneCommand()
{
    Document document;

    auto id1 = document.addItem(Circle);
    document.setItemProperty(id1, PositionProperty, QPointF(123, 456));
    document.setItemProperty(id1, RadiusProperty, 3.14);

    auto id2 = document.addItem(Circle);
    document.setItemProperty(id2, PositionProperty, QPointF(321, 654));
    document.setItemProperty(id2, RadiusProperty, 6.28);

    auto command = new CloneCommand();
    command->itemIdList = QList<quint64>() << id1 << id2;
    command->translation = QPointF(100, 200);
    command->setDocument(&document);

    command->redo();
    QCOMPARE(document.itemIdList().count(), 4);
    auto cloneId1 = document.itemIdList().value(2);
    QCOMPARE(document.itemProperty(id1, PositionProperty).toPointF(), QPointF(123, 456));
    QCOMPARE(document.itemProperty(id1, RadiusProperty).toReal(), 3.14);
    QCOMPARE(document.itemProperty(cloneId1, PositionProperty).toPointF(), QPointF(123+100, 456+200));
    QCOMPARE(document.itemProperty(cloneId1, RadiusProperty).toReal(), 3.14);
    auto cloneId2 = document.itemIdList().value(3);
    QCOMPARE(document.itemProperty(id2, PositionProperty).toPointF(), QPointF(321, 654));
    QCOMPARE(document.itemProperty(id2, RadiusProperty).toReal(), 6.28);
    QCOMPARE(document.itemProperty(cloneId2, PositionProperty).toPointF(), QPointF(321+100, 654+200));
    QCOMPARE(document.itemProperty(cloneId2, RadiusProperty).toReal(), 6.28);

    command->undo();
    QCOMPARE(document.itemIdList().count(), 2);
    QCOMPARE(document.itemProperty(id1, PositionProperty).toPointF(), QPointF(123, 456));
    QCOMPARE(document.itemProperty(id1, RadiusProperty).toReal(), 3.14);
    QCOMPARE(document.itemProperty(id2, PositionProperty).toPointF(), QPointF(321, 654));
    QCOMPARE(document.itemProperty(id2, RadiusProperty).toReal(), 6.28);

    // redo after undo should gives same IDs
    command->redo();
    QCOMPARE(document.itemIdList().count(), 4);
    QVERIFY(document.itemIdList().value(2) == cloneId1);
    QCOMPARE(document.itemProperty(id1, PositionProperty).toPointF(), QPointF(123, 456));
    QCOMPARE(document.itemProperty(id1, RadiusProperty).toReal(), 3.14);
    QCOMPARE(document.itemProperty(cloneId1, PositionProperty).toPointF(), QPointF(123+100, 456+200));
    QCOMPARE(document.itemProperty(cloneId1, RadiusProperty).toReal(), 3.14);
    QVERIFY(document.itemIdList().value(3) == cloneId2);
    QCOMPARE(document.itemProperty(id2, PositionProperty).toPointF(), QPointF(321, 654));
    QCOMPARE(document.itemProperty(id2, RadiusProperty).toReal(), 6.28);
    QCOMPARE(document.itemProperty(cloneId2, PositionProperty).toPointF(), QPointF(321+100, 654+200));
    QCOMPARE(document.itemProperty(cloneId2, RadiusProperty).toReal(), 6.28);
}

void tst_Document::moveCommand()
{
    Document document;

    auto id1 = document.addItem(Circle);
    document.setItemProperty(id1, PositionProperty, QPointF(123, 456));

    auto id2 = document.addItem(Circle);
    document.setItemProperty(id2, PositionProperty, QPointF(321, 654));

    auto command = new TranslateCommand();
    command->itemIdList = QList<quint64>() << id1 << id2;
    command->amount = QPointF(100, 200);
    command->setDocument(&document);

    command->redo();
    QCOMPARE(document.itemProperty(id1, PositionProperty).toPointF(), QPointF(123+100, 456+200));
    QCOMPARE(document.itemProperty(id2, PositionProperty).toPointF(), QPointF(321+100, 654+200));

    command->undo();
    QCOMPARE(document.itemProperty(id1, PositionProperty).toPointF(), QPointF(123, 456));
    QCOMPARE(document.itemProperty(id2, PositionProperty).toPointF(), QPointF(321, 654));

    command->redo();
    QCOMPARE(document.itemProperty(id1, PositionProperty).toPointF(), QPointF(123+100, 456+200));
    QCOMPARE(document.itemProperty(id2, PositionProperty).toPointF(), QPointF(321+100, 654+200));
}

void tst_Document::placeCircleCommand()
{
    Document document;

    auto command = new AddItemCommand();
    command->setItemType(Circle);
    command->setItemProperty(PositionProperty, QPointF(123, 456));
    command->setItemProperty(RadiusProperty, 3.14);
    command->setItemProperty(RotationProperty, 90.0);
    command->setItemProperty(OpacityProperty, 42.0);
    command->setItemProperty(XMirroredProperty, true);
    command->setItemProperty(YMirroredProperty, true);
    command->setItemProperty(LockedProperty, true);
    command->setItemProperty(VisibilityProperty, false);
    command->setItemProperty(LineColorProperty, QVariant::fromValue(Green));
    command->setItemProperty(LineWidthProperty, QVariant::fromValue(ThickestLine));
    command->setItemProperty(LineStyleProperty, QVariant::fromValue(DashDotDotLine));
    command->setItemProperty(FillColorProperty, QVariant::fromValue(Red));
    command->setItemProperty(FillStyleProperty, QVariant::fromValue(NoFill));
    command->setDocument(&document);

    command->redo();
    QCOMPARE(document.itemIdList().count(), 1);
    auto id = document.itemIdList().value(0);
    QCOMPARE(document.item(id)->type(), Circle);
    QCOMPARE(document.itemProperty(id, PositionProperty).toPointF(), QPointF(123, 456));
    QCOMPARE(document.itemProperty(id, RadiusProperty).toReal(), qreal(3.14));
    QCOMPARE(document.itemProperty(id, RotationProperty).toReal(), qreal(90));
    QCOMPARE(document.itemProperty(id, OpacityProperty).toReal(), qreal(42));
    QCOMPARE(document.itemProperty(id, XMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, YMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, LockedProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, VisibilityProperty).toBool(), false);
    QCOMPARE(document.itemProperty(id, LineColorProperty).value<Color>(), Green);
    QCOMPARE(document.itemProperty(id, LineStyleProperty).value<LineStyle>(), DashDotDotLine);
    QCOMPARE(document.itemProperty(id, LineWidthProperty).value<LineWidth>(), ThickestLine);
    QCOMPARE(document.itemProperty(id, FillColorProperty).value<Color>(), Red);
    QCOMPARE(document.itemProperty(id, FillStyleProperty).value<FillStyle>(), NoFill);

    command->undo();
    QCOMPARE(document.itemIdList().count(), 0);

    command->redo();
    QCOMPARE(document.itemIdList().count(), 1);
    QCOMPARE(document.itemIdList().value(0), id);
    QCOMPARE(document.item(id)->type(), Circle);
    QCOMPARE(document.itemProperty(id, PositionProperty).toPointF(), QPointF(123, 456));
    QCOMPARE(document.itemProperty(id, RadiusProperty).toReal(), qreal(3.14));
    QCOMPARE(document.itemProperty(id, RotationProperty).toReal(), qreal(90));
    QCOMPARE(document.itemProperty(id, OpacityProperty).toReal(), qreal(42));
    QCOMPARE(document.itemProperty(id, XMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, YMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, LockedProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, VisibilityProperty).toBool(), false);
    QCOMPARE(document.itemProperty(id, LineColorProperty).value<Color>(), Green);
    QCOMPARE(document.itemProperty(id, LineStyleProperty).value<LineStyle>(), DashDotDotLine);
    QCOMPARE(document.itemProperty(id, LineWidthProperty).value<LineWidth>(), ThickestLine);
    QCOMPARE(document.itemProperty(id, FillColorProperty).value<Color>(), Red);
    QCOMPARE(document.itemProperty(id, FillStyleProperty).value<FillStyle>(), NoFill);
}

void tst_Document::placeCircularArcCommand()
{
    Document document;

    auto command = new AddItemCommand();
    command->setItemType(CircularArc);
    command->setItemProperty(PositionProperty, QPointF(123, 456));
    command->setItemProperty(RadiusProperty, 3.14);
    command->setItemProperty(StartAngleProperty, 6.28);
    command->setItemProperty(SpanAngleProperty, 9.42);
    command->setItemProperty(RotationProperty, 90.0);
    command->setItemProperty(OpacityProperty, 42.0);
    command->setItemProperty(XMirroredProperty, true);
    command->setItemProperty(YMirroredProperty, true);
    command->setItemProperty(LockedProperty, true);
    command->setItemProperty(VisibilityProperty, false);
    command->setItemProperty(LineColorProperty, QVariant::fromValue(Green));
    command->setItemProperty(LineWidthProperty, QVariant::fromValue(ThickestLine));
    command->setItemProperty(LineStyleProperty, QVariant::fromValue(DashDotDotLine));
    command->setItemProperty(FillColorProperty, QVariant::fromValue(Red));
    command->setItemProperty(FillStyleProperty, QVariant::fromValue(NoFill));
    command->setDocument(&document);

    command->redo();
    QCOMPARE(document.itemIdList().count(), 1);
    auto id = document.itemIdList().value(0);
    QCOMPARE(document.item(id)->type(), CircularArc);
    QCOMPARE(document.itemProperty(id, PositionProperty).toPointF(), QPointF(123, 456));
    QCOMPARE(document.itemProperty(id, RadiusProperty).toReal(), qreal(3.14));
    QCOMPARE(document.itemProperty(id, StartAngleProperty).toReal(), qreal(6.28));
    QCOMPARE(document.itemProperty(id, SpanAngleProperty).toReal(), qreal(9.42));
    QCOMPARE(document.itemProperty(id, RotationProperty).toReal(), qreal(90));
    QCOMPARE(document.itemProperty(id, OpacityProperty).toReal(), qreal(42));
    QCOMPARE(document.itemProperty(id, XMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, YMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, LockedProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, VisibilityProperty).toBool(), false);
    QCOMPARE(document.itemProperty(id, LineColorProperty).value<Color>(), Green);
    QCOMPARE(document.itemProperty(id, LineStyleProperty).value<LineStyle>(), DashDotDotLine);
    QCOMPARE(document.itemProperty(id, LineWidthProperty).value<LineWidth>(), ThickestLine);
    QCOMPARE(document.itemProperty(id, FillColorProperty).value<Color>(), Red);
    QCOMPARE(document.itemProperty(id, FillStyleProperty).value<FillStyle>(), NoFill);

    command->undo();
    QCOMPARE(document.itemIdList().count(), 0);

    command->redo();
    QCOMPARE(document.itemIdList().count(), 1);
    QCOMPARE(document.itemIdList().value(0), id);
    QCOMPARE(document.item(id)->type(), CircularArc);
    QCOMPARE(document.itemProperty(id, PositionProperty).toPointF(), QPointF(123, 456));
    QCOMPARE(document.itemProperty(id, RadiusProperty).toReal(), qreal(3.14));
    QCOMPARE(document.itemProperty(id, StartAngleProperty).toReal(), qreal(6.28));
    QCOMPARE(document.itemProperty(id, SpanAngleProperty).toReal(), qreal(9.42));
    QCOMPARE(document.itemProperty(id, RotationProperty).toReal(), qreal(90));
    QCOMPARE(document.itemProperty(id, OpacityProperty).toReal(), qreal(42));
    QCOMPARE(document.itemProperty(id, XMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, YMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, LockedProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, VisibilityProperty).toBool(), false);
    QCOMPARE(document.itemProperty(id, LineColorProperty).value<Color>(), Green);
    QCOMPARE(document.itemProperty(id, LineStyleProperty).value<LineStyle>(), DashDotDotLine);
    QCOMPARE(document.itemProperty(id, LineWidthProperty).value<LineWidth>(), ThickestLine);
    QCOMPARE(document.itemProperty(id, FillColorProperty).value<Color>(), Red);
    QCOMPARE(document.itemProperty(id, FillStyleProperty).value<FillStyle>(), NoFill);
}

void tst_Document::placeEllipseCommand()
{
    Document document;

    auto command = new AddItemCommand();
    command->setItemType(Ellipse);
    command->setItemProperty(PositionProperty, QPointF(123, 456));
    command->setItemProperty(XRadiusProperty, 3.14);
    command->setItemProperty(YRadiusProperty, 6.28);
    command->setItemProperty(RotationProperty, 90.0);
    command->setItemProperty(OpacityProperty, 42.0);
    command->setItemProperty(XMirroredProperty, true);
    command->setItemProperty(YMirroredProperty, true);
    command->setItemProperty(LockedProperty, true);
    command->setItemProperty(VisibilityProperty, false);
    command->setItemProperty(LineColorProperty, QVariant::fromValue(Green));
    command->setItemProperty(LineWidthProperty, QVariant::fromValue(ThickestLine));
    command->setItemProperty(LineStyleProperty, QVariant::fromValue(DashDotDotLine));
    command->setItemProperty(FillColorProperty, QVariant::fromValue(Red));
    command->setItemProperty(FillStyleProperty, QVariant::fromValue(NoFill));
    command->setDocument(&document);

    command->redo();
    QCOMPARE(document.itemIdList().count(), 1);
    auto id = document.itemIdList().value(0);
    QCOMPARE(document.item(id)->type(), Ellipse);
    QCOMPARE(document.itemProperty(id, PositionProperty).toPointF(), QPointF(123, 456));
    QCOMPARE(document.itemProperty(id, XRadiusProperty).toReal(), qreal(3.14));
    QCOMPARE(document.itemProperty(id, YRadiusProperty).toReal(), qreal(6.28));
    QCOMPARE(document.itemProperty(id, RotationProperty).toReal(), qreal(90));
    QCOMPARE(document.itemProperty(id, OpacityProperty).toReal(), qreal(42));
    QCOMPARE(document.itemProperty(id, XMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, YMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, LockedProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, VisibilityProperty).toBool(), false);
    QCOMPARE(document.itemProperty(id, LineColorProperty).value<Color>(), Green);
    QCOMPARE(document.itemProperty(id, LineStyleProperty).value<LineStyle>(), DashDotDotLine);
    QCOMPARE(document.itemProperty(id, LineWidthProperty).value<LineWidth>(), ThickestLine);
    QCOMPARE(document.itemProperty(id, FillColorProperty).value<Color>(), Red);
    QCOMPARE(document.itemProperty(id, FillStyleProperty).value<FillStyle>(), NoFill);

    command->undo();
    QCOMPARE(document.itemIdList().count(), 0);

    command->redo();
    QCOMPARE(document.itemIdList().count(), 1);
    QCOMPARE(document.itemIdList().value(0), id);
    QCOMPARE(document.item(id)->type(), Ellipse);
    QCOMPARE(document.itemProperty(id, PositionProperty).toPointF(), QPointF(123, 456));
    QCOMPARE(document.itemProperty(id, XRadiusProperty).toReal(), qreal(3.14));
    QCOMPARE(document.itemProperty(id, YRadiusProperty).toReal(), qreal(6.28));
    QCOMPARE(document.itemProperty(id, RotationProperty).toReal(), qreal(90));
    QCOMPARE(document.itemProperty(id, OpacityProperty).toReal(), qreal(42));
    QCOMPARE(document.itemProperty(id, XMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, YMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, LockedProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, VisibilityProperty).toBool(), false);
    QCOMPARE(document.itemProperty(id, LineColorProperty).value<Color>(), Green);
    QCOMPARE(document.itemProperty(id, LineStyleProperty).value<LineStyle>(), DashDotDotLine);
    QCOMPARE(document.itemProperty(id, LineWidthProperty).value<LineWidth>(), ThickestLine);
    QCOMPARE(document.itemProperty(id, FillColorProperty).value<Color>(), Red);
    QCOMPARE(document.itemProperty(id, FillStyleProperty).value<FillStyle>(), NoFill);
}

void tst_Document::placeEllipticalArcCommand()
{
    Document document;

    auto command = new AddItemCommand();
    command->setItemType(EllipticalArc);
    command->setItemProperty(PositionProperty, QPointF(123, 456));
    command->setItemProperty(XRadiusProperty, 3.14);
    command->setItemProperty(YRadiusProperty, 6.28);
    command->setItemProperty(StartAngleProperty, 9.42);
    command->setItemProperty(SpanAngleProperty, 12.56);
    command->setItemProperty(RotationProperty, 90.0);
    command->setItemProperty(OpacityProperty, 42.0);
    command->setItemProperty(XMirroredProperty, true);
    command->setItemProperty(YMirroredProperty, true);
    command->setItemProperty(LockedProperty, true);
    command->setItemProperty(VisibilityProperty, false);
    command->setItemProperty(LineColorProperty, QVariant::fromValue(Green));
    command->setItemProperty(LineWidthProperty, QVariant::fromValue(ThickestLine));
    command->setItemProperty(LineStyleProperty, QVariant::fromValue(DashDotDotLine));
    command->setItemProperty(FillColorProperty, QVariant::fromValue(Red));
    command->setItemProperty(FillStyleProperty, QVariant::fromValue(NoFill));
    command->setDocument(&document);

    command->redo();
    QCOMPARE(document.itemIdList().count(), 1);
    auto id = document.itemIdList().value(0);
    QCOMPARE(document.item(id)->type(), EllipticalArc);
    QCOMPARE(document.itemProperty(id, PositionProperty).toPointF(), QPointF(123, 456));
    QCOMPARE(document.itemProperty(id, XRadiusProperty).toReal(), qreal(3.14));
    QCOMPARE(document.itemProperty(id, YRadiusProperty).toReal(), qreal(6.28));
    QCOMPARE(document.itemProperty(id, StartAngleProperty).toReal(), qreal(9.42));
    QCOMPARE(document.itemProperty(id, SpanAngleProperty).toReal(), qreal(12.56));
    QCOMPARE(document.itemProperty(id, RotationProperty).toReal(), qreal(90));
    QCOMPARE(document.itemProperty(id, OpacityProperty).toReal(), qreal(42));
    QCOMPARE(document.itemProperty(id, XMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, YMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, LockedProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, VisibilityProperty).toBool(), false);
    QCOMPARE(document.itemProperty(id, LineColorProperty).value<Color>(), Green);
    QCOMPARE(document.itemProperty(id, LineStyleProperty).value<LineStyle>(), DashDotDotLine);
    QCOMPARE(document.itemProperty(id, LineWidthProperty).value<LineWidth>(), ThickestLine);
    QCOMPARE(document.itemProperty(id, FillColorProperty).value<Color>(), Red);
    QCOMPARE(document.itemProperty(id, FillStyleProperty).value<FillStyle>(), NoFill);

    command->undo();
    QCOMPARE(document.itemIdList().count(), 0);

    command->redo();
    QCOMPARE(document.itemIdList().count(), 1);
    QCOMPARE(document.itemIdList().value(0), id);
    QCOMPARE(document.item(id)->type(), EllipticalArc);
    QCOMPARE(document.itemProperty(id, PositionProperty).toPointF(), QPointF(123, 456));
    QCOMPARE(document.itemProperty(id, XRadiusProperty).toReal(), qreal(3.14));
    QCOMPARE(document.itemProperty(id, YRadiusProperty).toReal(), qreal(6.28));
    QCOMPARE(document.itemProperty(id, StartAngleProperty).toReal(), qreal(9.42));
    QCOMPARE(document.itemProperty(id, SpanAngleProperty).toReal(), qreal(12.56));
    QCOMPARE(document.itemProperty(id, RotationProperty).toReal(), qreal(90));
    QCOMPARE(document.itemProperty(id, OpacityProperty).toReal(), qreal(42));
    QCOMPARE(document.itemProperty(id, XMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, YMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, LockedProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, VisibilityProperty).toBool(), false);
    QCOMPARE(document.itemProperty(id, LineColorProperty).value<Color>(), Green);
    QCOMPARE(document.itemProperty(id, LineStyleProperty).value<LineStyle>(), DashDotDotLine);
    QCOMPARE(document.itemProperty(id, LineWidthProperty).value<LineWidth>(), ThickestLine);
    QCOMPARE(document.itemProperty(id, FillColorProperty).value<Color>(), Red);
    QCOMPARE(document.itemProperty(id, FillStyleProperty).value<FillStyle>(), NoFill);
}

void tst_Document::placeRectangleCommand()
{
    Document document;

    auto command = new AddItemCommand();
    command->setItemType(Rectangle);
    command->setItemProperty(PositionProperty, QPointF(123, 456));
    command->setItemProperty(WidthProperty, 3.14);
    command->setItemProperty(HeightProperty, 6.28);
    command->setItemProperty(RotationProperty, 90.0);
    command->setItemProperty(OpacityProperty, 42.0);
    command->setItemProperty(XMirroredProperty, true);
    command->setItemProperty(YMirroredProperty, true);
    command->setItemProperty(LockedProperty, true);
    command->setItemProperty(VisibilityProperty, false);
    command->setItemProperty(LineColorProperty, QVariant::fromValue(Green));
    command->setItemProperty(LineWidthProperty, QVariant::fromValue(ThickestLine));
    command->setItemProperty(LineStyleProperty, QVariant::fromValue(DashDotDotLine));
    command->setItemProperty(FillColorProperty, QVariant::fromValue(Red));
    command->setItemProperty(FillStyleProperty, QVariant::fromValue(NoFill));
    command->setDocument(&document);

    command->redo();
    QCOMPARE(document.itemIdList().count(), 1);
    auto id = document.itemIdList().value(0);
    QCOMPARE(document.item(id)->type(), Rectangle);
    QCOMPARE(document.itemProperty(id, PositionProperty).toPointF(), QPointF(123, 456));
    QCOMPARE(document.itemProperty(id, WidthProperty).toReal(), qreal(3.14));
    QCOMPARE(document.itemProperty(id, HeightProperty).toReal(), qreal(6.28));
    QCOMPARE(document.itemProperty(id, RotationProperty).toReal(), qreal(90));
    QCOMPARE(document.itemProperty(id, OpacityProperty).toReal(), qreal(42));
    QCOMPARE(document.itemProperty(id, XMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, YMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, LockedProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, VisibilityProperty).toBool(), false);
    QCOMPARE(document.itemProperty(id, LineColorProperty).value<Color>(), Green);
    QCOMPARE(document.itemProperty(id, LineStyleProperty).value<LineStyle>(), DashDotDotLine);
    QCOMPARE(document.itemProperty(id, LineWidthProperty).value<LineWidth>(), ThickestLine);
    QCOMPARE(document.itemProperty(id, FillColorProperty).value<Color>(), Red);
    QCOMPARE(document.itemProperty(id, FillStyleProperty).value<FillStyle>(), NoFill);

    command->undo();
    QCOMPARE(document.itemIdList().count(), 0);

    command->redo();
    QCOMPARE(document.itemIdList().count(), 1);
    QCOMPARE(document.itemIdList().value(0), id);
    QCOMPARE(document.item(id)->type(), Rectangle);
    QCOMPARE(document.itemProperty(id, PositionProperty).toPointF(), QPointF(123, 456));
    QCOMPARE(document.itemProperty(id, WidthProperty).toReal(), qreal(3.14));
    QCOMPARE(document.itemProperty(id, HeightProperty).toReal(), qreal(6.28));
    QCOMPARE(document.itemProperty(id, RotationProperty).toReal(), qreal(90));
    QCOMPARE(document.itemProperty(id, OpacityProperty).toReal(), qreal(42));
    QCOMPARE(document.itemProperty(id, XMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, YMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, LockedProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, VisibilityProperty).toBool(), false);
    QCOMPARE(document.itemProperty(id, LineColorProperty).value<Color>(), Green);
    QCOMPARE(document.itemProperty(id, LineStyleProperty).value<LineStyle>(), DashDotDotLine);
    QCOMPARE(document.itemProperty(id, LineWidthProperty).value<LineWidth>(), ThickestLine);
    QCOMPARE(document.itemProperty(id, FillColorProperty).value<Color>(), Red);
    QCOMPARE(document.itemProperty(id, FillStyleProperty).value<FillStyle>(), NoFill);
}

void tst_Document::placePolylineCommand()
{
    Document document;

    QList<QPointF> vertices;
    vertices << QPointF(123,234) << QPointF(345, 456);
    QVariant variantVertices = QVariant::fromValue<QList<QPointF>>(vertices);

    auto command = new AddItemCommand();
    command->setItemType(Polyline);
    command->setItemProperty(PositionProperty, QPointF(123, 456));
    command->setItemProperty(VerticesProperty, variantVertices);
    command->setItemProperty(RotationProperty, 90.0);
    command->setItemProperty(OpacityProperty, 42.0);
    command->setItemProperty(XMirroredProperty, true);
    command->setItemProperty(YMirroredProperty, true);
    command->setItemProperty(LockedProperty, true);
    command->setItemProperty(VisibilityProperty, false);
    command->setItemProperty(LineColorProperty, QVariant::fromValue(Green));
    command->setItemProperty(LineWidthProperty, QVariant::fromValue(ThickestLine));
    command->setItemProperty(LineStyleProperty, QVariant::fromValue(DashDotDotLine));
    command->setItemProperty(FillColorProperty, QVariant::fromValue(Red));
    command->setItemProperty(FillStyleProperty, QVariant::fromValue(NoFill));
    command->setDocument(&document);

    command->redo();
    QCOMPARE(document.itemIdList().count(), 1);
    auto id = document.itemIdList().value(0);
    QCOMPARE(document.item(id)->type(), Polyline);
    QCOMPARE(document.itemProperty(id, VerticesProperty), variantVertices);
    QCOMPARE(document.itemProperty(id, PositionProperty).toPointF(), QPointF(123, 456));
    QCOMPARE(document.itemProperty(id, RotationProperty).toReal(), qreal(90));
    QCOMPARE(document.itemProperty(id, OpacityProperty).toReal(), qreal(42));
    QCOMPARE(document.itemProperty(id, XMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, YMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, LockedProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, VisibilityProperty).toBool(), false);
    QCOMPARE(document.itemProperty(id, LineColorProperty).value<Color>(), Green);
    QCOMPARE(document.itemProperty(id, LineStyleProperty).value<LineStyle>(), DashDotDotLine);
    QCOMPARE(document.itemProperty(id, LineWidthProperty).value<LineWidth>(), ThickestLine);
    QCOMPARE(document.itemProperty(id, FillColorProperty).value<Color>(), Red);
    QCOMPARE(document.itemProperty(id, FillStyleProperty).value<FillStyle>(), NoFill);

    command->undo();
    QCOMPARE(document.itemIdList().count(), 0);

    command->redo();
    QCOMPARE(document.itemIdList().count(), 1);
    QCOMPARE(document.itemIdList().value(0), id);
    QCOMPARE(document.item(id)->type(), Polyline);
    QCOMPARE(document.itemProperty(id, VerticesProperty), variantVertices);
    QCOMPARE(document.itemProperty(id, PositionProperty).toPointF(), QPointF(123, 456));
    QCOMPARE(document.itemProperty(id, RotationProperty).toReal(), qreal(90));
    QCOMPARE(document.itemProperty(id, OpacityProperty).toReal(), qreal(42));
    QCOMPARE(document.itemProperty(id, XMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, YMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, LockedProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, VisibilityProperty).toBool(), false);
    QCOMPARE(document.itemProperty(id, LineColorProperty).value<Color>(), Green);
    QCOMPARE(document.itemProperty(id, LineStyleProperty).value<LineStyle>(), DashDotDotLine);
    QCOMPARE(document.itemProperty(id, LineWidthProperty).value<LineWidth>(), ThickestLine);
    QCOMPARE(document.itemProperty(id, FillColorProperty).value<Color>(), Red);
    QCOMPARE(document.itemProperty(id, FillStyleProperty).value<FillStyle>(), NoFill);

}

void tst_Document::placePolygonCommand()
{
    Document document;

    QList<QPointF> vertices;
    vertices << QPointF(123,234) << QPointF(345, 456);
    QVariant variantVertices = QVariant::fromValue<QList<QPointF>>(vertices);

    auto command = new AddItemCommand();
    command->setItemType(Polygon);
    command->setItemProperty(PositionProperty, QPointF(123, 456));
    command->setItemProperty(VerticesProperty, variantVertices);
    command->setItemProperty(RotationProperty, 90.0);
    command->setItemProperty(OpacityProperty, 42.0);
    command->setItemProperty(XMirroredProperty, true);
    command->setItemProperty(YMirroredProperty, true);
    command->setItemProperty(LockedProperty, true);
    command->setItemProperty(VisibilityProperty, false);
    command->setItemProperty(LineColorProperty, QVariant::fromValue(Green));
    command->setItemProperty(LineWidthProperty, QVariant::fromValue(ThickestLine));
    command->setItemProperty(LineStyleProperty, QVariant::fromValue(DashDotDotLine));
    command->setItemProperty(FillColorProperty, QVariant::fromValue(Red));
    command->setItemProperty(FillStyleProperty, QVariant::fromValue(NoFill));
    command->setDocument(&document);

    command->redo();
    QCOMPARE(document.itemIdList().count(), 1);
    auto id = document.itemIdList().value(0);
    QCOMPARE(document.item(id)->type(), Polygon);
    QCOMPARE(document.itemProperty(id, VerticesProperty), variantVertices);
    QCOMPARE(document.itemProperty(id, PositionProperty).toPointF(), QPointF(123, 456));
    QCOMPARE(document.itemProperty(id, RotationProperty).toReal(), qreal(90));
    QCOMPARE(document.itemProperty(id, OpacityProperty).toReal(), qreal(42));
    QCOMPARE(document.itemProperty(id, XMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, YMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, LockedProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, VisibilityProperty).toBool(), false);
    QCOMPARE(document.itemProperty(id, LineColorProperty).value<Color>(), Green);
    QCOMPARE(document.itemProperty(id, LineStyleProperty).value<LineStyle>(), DashDotDotLine);
    QCOMPARE(document.itemProperty(id, LineWidthProperty).value<LineWidth>(), ThickestLine);
    QCOMPARE(document.itemProperty(id, FillColorProperty).value<Color>(), Red);
    QCOMPARE(document.itemProperty(id, FillStyleProperty).value<FillStyle>(), NoFill);

    command->undo();
    QCOMPARE(document.itemIdList().count(), 0);

    command->redo();
    QCOMPARE(document.itemIdList().count(), 1);
    QCOMPARE(document.itemIdList().value(0), id);
    QCOMPARE(document.item(id)->type(), Polygon);
    QCOMPARE(document.itemProperty(id, VerticesProperty), variantVertices);
    QCOMPARE(document.itemProperty(id, PositionProperty).toPointF(), QPointF(123, 456));
    QCOMPARE(document.itemProperty(id, RotationProperty).toReal(), qreal(90));
    QCOMPARE(document.itemProperty(id, OpacityProperty).toReal(), qreal(42));
    QCOMPARE(document.itemProperty(id, XMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, YMirroredProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, LockedProperty).toBool(), true);
    QCOMPARE(document.itemProperty(id, VisibilityProperty).toBool(), false);
    QCOMPARE(document.itemProperty(id, LineColorProperty).value<Color>(), Green);
    QCOMPARE(document.itemProperty(id, LineStyleProperty).value<LineStyle>(), DashDotDotLine);
    QCOMPARE(document.itemProperty(id, LineWidthProperty).value<LineWidth>(), ThickestLine);
    QCOMPARE(document.itemProperty(id, FillColorProperty).value<Color>(), Red);
    QCOMPARE(document.itemProperty(id, FillStyleProperty).value<FillStyle>(), NoFill);
}

void tst_Document::placePinCommand()
{

}

void tst_Document::placeLabelCommand()
{

}

void tst_Document::alignLeftCommand()
{
    Document document;

    RectangleItem refItem;
    refItem.setPosition(50, 50);
    refItem.setWidth(30);
    refItem.setHeight(30);
    auto refId = document.addItem(&refItem);

    CircleItem circle;
    circle.setPosition(100, 20);
    circle.setRadius(80);
    auto circleId = document.addItem(&circle);

    AlignCommand command;
    command.setAlignment(Qt::AlignLeft);
    command.setItems(QList<quint64>() << refId << circleId);
    command.setDocument(&document);

    command.redo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(50 + 80, 20));

    command.undo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(100, 20));
}

void tst_Document::alignHCenterCommand()
{
    Document document;

    RectangleItem refItem;
    refItem.setPosition(50, 50);
    refItem.setWidth(30);
    refItem.setHeight(30);
    auto refId = document.addItem(&refItem);

    CircleItem circle;
    circle.setPosition(100, 20);
    circle.setRadius(80);
    auto circleId = document.addItem(&circle);

    AlignCommand command;
    command.setAlignment(Qt::AlignHCenter);
    command.setItems(QList<quint64>() << refId << circleId);
    command.setDocument(&document);

    command.redo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(50 + 30/2.0, 20));

    command.undo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(100, 20));
}

void tst_Document::alignRightCommand()
{
    Document document;

    RectangleItem refItem;
    refItem.setPosition(50, 50);
    refItem.setWidth(30);
    refItem.setHeight(30);
    auto refId = document.addItem(&refItem);

    CircleItem circle;
    circle.setPosition(100, 20);
    circle.setRadius(80);
    auto circleId = document.addItem(&circle);

    AlignCommand command;
    command.setAlignment(Qt::AlignRight);
    command.setItems(QList<quint64>() << refId << circleId);
    command.setDocument(&document);

    command.redo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(50 + 30 - 80, 20));

    command.undo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(100, 20));
}

void tst_Document::alignTopCommand()
{
    Document document;

    RectangleItem refItem;
    refItem.setPosition(50, 50);
    refItem.setWidth(30);
    refItem.setHeight(30);
    auto refId = document.addItem(&refItem);

    CircleItem circle;
    circle.setPosition(100, 20);
    circle.setRadius(80);
    auto circleId = document.addItem(&circle);

    AlignCommand command;
    command.setAlignment(Qt::AlignTop);
    command.setItems(QList<quint64>() << refId << circleId);
    command.setDocument(&document);

    command.redo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(100, 50 + 80));

    command.undo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(100, 20));
}

void tst_Document::alignVCenterCommand()
{
    Document document;

    RectangleItem refItem;
    refItem.setPosition(50, 50);
    refItem.setWidth(30);
    refItem.setHeight(30);
    auto refId = document.addItem(&refItem);

    CircleItem circle;
    circle.setPosition(100, 20);
    circle.setRadius(80);
    auto circleId = document.addItem(&circle);

    AlignCommand command;
    command.setAlignment(Qt::AlignVCenter);
    command.setItems(QList<quint64>() << refId << circleId);
    command.setDocument(&document);

    command.redo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(100, 50 + 30/2.0));

    command.undo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(100, 20));
}

void tst_Document::alignBottomCommand()
{
    Document document;

    RectangleItem refItem;
    refItem.setPosition(50, 50);
    refItem.setWidth(30);
    refItem.setHeight(30);
    auto refId = document.addItem(&refItem);

    CircleItem circle;
    circle.setPosition(100, 20);
    circle.setRadius(80);
    auto circleId = document.addItem(&circle);

    AlignCommand command;
    command.setAlignment(Qt::AlignBottom);
    command.setItems(QList<quint64>() << refId << circleId);
    command.setDocument(&document);

    command.redo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(100, 50 + 30 - 80));

    command.undo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(100, 20));
}

void tst_Document::alignCommandWithItemTransform()
{

    Document document;

    CircleItem refItem;
    refItem.setPosition(100, 20);
    refItem.setRadius(80);
    auto refId = document.addItem(&refItem);

    RectangleItem rect;
    rect.setPosition(50, 50);
    rect.setWidth(30);
    rect.setHeight(100);
    rect.setXMirrored(true);
    rect.setYMirrored(true);
    auto rectId = document.addItem(&rect);

    AlignCommand command1;
    command1.setAlignment(Qt::AlignVCenter);
    command1.setItems(QList<quint64>() << refId << rectId);
    command1.setDocument(&document);
    AlignCommand command2;
    command2.setAlignment(Qt::AlignHCenter);
    command2.setItems(QList<quint64>() << refId << rectId);
    command2.setDocument(&document);

    command1.redo();
    command2.redo();
    QCOMPARE(refItem.position(), QPointF(100, 20));
    QCOMPARE(rect.position(), QPointF(100 + 30/2.0, 20 + 100/2.0));

    command1.undo();
    command2.undo();
    QCOMPARE(refItem.position(), QPointF(100, 20));
    QCOMPARE(rect.position(), QPointF(50, 50));
}

void tst_Document::distributeLeftBorders()
{
    Document document;

    RectangleItem refItem;
    refItem.setPosition(50, 50);
    refItem.setWidth(30);
    refItem.setHeight(30);
    auto refId = document.addItem(&refItem);

    CircleItem circle;
    circle.setPosition(100, 20);
    circle.setRadius(80);
    auto circleId = document.addItem(&circle);

    DistributeCommand command;
    command.setDistribution(DistributeLeftBorders);
    command.setDistance(75);
    command.setItems(QList<quint64>() << refId << circleId);
    command.setDocument(&document);

    command.redo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(75 + 50 + 80, 20));

    command.undo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(100, 20));

}

void tst_Document::distributeHCenters()
{
    Document document;

    RectangleItem refItem;
    refItem.setPosition(50, 50);
    refItem.setWidth(30);
    refItem.setHeight(30);
    auto refId = document.addItem(&refItem);

    CircleItem circle;
    circle.setPosition(100, 20);
    circle.setRadius(80);
    auto circleId = document.addItem(&circle);

    DistributeCommand command;
    command.setDistribution(DistributeHCenters);
    command.setDistance(75);
    command.setItems(QList<quint64>() << refId << circleId);
    command.setDocument(&document);

    command.redo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(75 + 50 + 30/2.0, 20));

    command.undo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(100, 20));
}

void tst_Document::distributeHGaps()
{
    Document document;

    RectangleItem refItem;
    refItem.setPosition(50, 50);
    refItem.setWidth(30);
    refItem.setHeight(30);
    auto refId = document.addItem(&refItem);

    CircleItem circle;
    circle.setPosition(100, 20);
    circle.setRadius(80);
    auto circleId = document.addItem(&circle);

    DistributeCommand command;
    command.setDistribution(DistributeHGaps);
    command.setDistance(75);
    command.setItems(QList<quint64>() << refId << circleId);
    command.setDocument(&document);

    command.redo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(50 + 30 + 75 + 80, 20));

    command.undo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(100, 20));
}

void tst_Document::distributeRightBorders()
{
    Document document;

    RectangleItem refItem;
    refItem.setPosition(50, 50);
    refItem.setWidth(30);
    refItem.setHeight(30);
    auto refId = document.addItem(&refItem);

    CircleItem circle;
    circle.setPosition(100, 20);
    circle.setRadius(80);
    auto circleId = document.addItem(&circle);

    DistributeCommand command;
    command.setDistribution(DistributeRightBorders);
    command.setDistance(75);
    command.setItems(QList<quint64>() << refId << circleId);
    command.setDocument(&document);

    command.redo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(50 + 30 + 75 - 80, 20));

    command.undo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(100, 20));
}

void tst_Document::distributeTopBorders()
{
    Document document;

    RectangleItem refItem;
    refItem.setPosition(50, 50);
    refItem.setWidth(30);
    refItem.setHeight(30);
    auto refId = document.addItem(&refItem);

    CircleItem circle;
    circle.setPosition(100, 20);
    circle.setRadius(80);
    auto circleId = document.addItem(&circle);

    DistributeCommand command;
    command.setDistribution(DistributeTopBorders);
    command.setDistance(75);
    command.setItems(QList<quint64>() << refId << circleId);
    command.setDocument(&document);

    command.redo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(100, 50 + 75 + 80));

    command.undo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(100, 20));
}

void tst_Document::distributeVCenters()
{
    Document document;

    RectangleItem refItem;
    refItem.setPosition(50, 50);
    refItem.setWidth(30);
    refItem.setHeight(30);
    auto refId = document.addItem(&refItem);

    CircleItem circle;
    circle.setPosition(100, 20);
    circle.setRadius(80);
    auto circleId = document.addItem(&circle);

    DistributeCommand command;
    command.setDistribution(DistributeVCenters);
    command.setDistance(75);
    command.setItems(QList<quint64>() << refId << circleId);
    command.setDocument(&document);

    command.redo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(100, 50 + 30/2.0 + 75));

    command.undo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(100, 20));
}

void tst_Document::distributeVGaps()
{
    Document document;

    RectangleItem refItem;
    refItem.setPosition(50, 50);
    refItem.setWidth(30);
    refItem.setHeight(30);
    auto refId = document.addItem(&refItem);

    CircleItem circle;
    circle.setPosition(100, 20);
    circle.setRadius(80);
    auto circleId = document.addItem(&circle);

    DistributeCommand command;
    command.setDistribution(DistributeVGaps);
    command.setDistance(75);
    command.setItems(QList<quint64>() << refId << circleId);
    command.setDocument(&document);

    command.redo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(100, 50 + 30 + 75 + 80));

    command.undo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(100, 20));
}

void tst_Document::distributeBottomBorders()
{
    Document document;

    RectangleItem refItem;
    refItem.setPosition(50, 50);
    refItem.setWidth(30);
    refItem.setHeight(30);
    auto refId = document.addItem(&refItem);

    CircleItem circle;
    circle.setPosition(100, 20);
    circle.setRadius(80);
    auto circleId = document.addItem(&circle);

    DistributeCommand command;
    command.setDistribution(DistributeBottomBorders);
    command.setDistance(75);
    command.setItems(QList<quint64>() << refId << circleId);
    command.setDocument(&document);

    command.redo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(100, 50 + 30 + 75 - 80));

    command.undo();
    QCOMPARE(refItem.position(), QPointF(50, 50));
    QCOMPARE(circle.position(), QPointF(100, 20));
}

void tst_Document::itemAreStackedInItemCreationOrder()
{
    Document document;

    auto id0 = document.addItem(new RectangleItem);
    auto id1 = document.addItem(new RectangleItem);
    auto id2 = document.addItem(new RectangleItem);
    auto id3 = document.addItem(new RectangleItem);
    auto id4 = document.addItem(new RectangleItem);

    QCOMPARE(document.itemStack(), QList<quint64>() << id0 << id1 << id2 << id3 << id4);
}

void tst_Document::removingItemsDoesntReshuffleStackOrder()
{
    Document document;

    auto id0 = document.addItem(new RectangleItem);
    auto id1 = document.addItem(new RectangleItem);
    auto id2 = document.addItem(new RectangleItem);
    auto id3 = document.addItem(new RectangleItem);
    auto id4 = document.addItem(new RectangleItem);

    document.removeItem(id1);
    document.removeItem(id3);

    QCOMPARE(document.itemStack(), QList<quint64>() << id0 << id2 << id4);
}

void tst_Document::movingTopItemToTopDoesNothing()
{
    Document document;

    auto id0 = document.addItem(new RectangleItem);
    auto id1 = document.addItem(new RectangleItem);
    auto id2 = document.addItem(new RectangleItem);
    auto id3 = document.addItem(new RectangleItem);
    auto id4 = document.addItem(new RectangleItem);

    StackOrderCommand command;
    command.setStackOperation(StackUp);
    command.setItem(id4);
    command.setReferenceItem(id4);
    command.setDocument(&document);

    command.redo();
    QCOMPARE(document.itemStack(), QList<quint64>() << id0 << id1 << id2 << id3 << id4);

    command.undo();
    QCOMPARE(document.itemStack(), QList<quint64>() << id0 << id1 << id2 << id3 << id4);
}

void tst_Document::stackUpSameDoesNothing()
{
    Document document;

    auto id0 = document.addItem(new RectangleItem);
    auto id1 = document.addItem(new RectangleItem);
    auto id2 = document.addItem(new RectangleItem);
    auto id3 = document.addItem(new RectangleItem);
    auto id4 = document.addItem(new RectangleItem);

    StackOrderCommand command;
    command.setStackOperation(StackUp);
    command.setItem(id2);
    command.setReferenceItem(id2);
    command.setDocument(&document);

    command.redo();
    QCOMPARE(document.itemStack(), QList<quint64>() << id0 << id1 << id2 << id3 << id4);

    command.undo();
    QCOMPARE(document.itemStack(), QList<quint64>() << id0 << id1 << id2 << id3 << id4);
}

void tst_Document::stackUpWorks()
{
    Document document;

    auto id0 = document.addItem(new RectangleItem);
    auto id1 = document.addItem(new RectangleItem);
    auto id2 = document.addItem(new RectangleItem);
    auto id3 = document.addItem(new RectangleItem);
    auto id4 = document.addItem(new RectangleItem);

    StackOrderCommand command;
    command.setStackOperation(StackUp);
    command.setItem(id1);
    command.setReferenceItem(id3);
    command.setDocument(&document);

    command.redo();
    QCOMPARE(document.itemStack(), QList<quint64>() << id0 << id2 << id3 << id1 << id4);

    command.undo();
    QCOMPARE(document.itemStack(), QList<quint64>() << id0 << id1 << id2 << id3 << id4);
}

void tst_Document::movingBottomItemToBottomDoesNothing()
{
    Document document;

    auto id0 = document.addItem(new RectangleItem);
    auto id1 = document.addItem(new RectangleItem);
    auto id2 = document.addItem(new RectangleItem);
    auto id3 = document.addItem(new RectangleItem);
    auto id4 = document.addItem(new RectangleItem);

    StackOrderCommand command;
    command.setStackOperation(StackDown);
    command.setItem(id0);
    command.setReferenceItem(id0);
    command.setDocument(&document);

    command.redo();
    QCOMPARE(document.itemStack(), QList<quint64>() << id0 << id1 << id2 << id3 << id4);

    command.undo();
    QCOMPARE(document.itemStack(), QList<quint64>() << id0 << id1 << id2 << id3 << id4);
}

void tst_Document::stackDownSameDoesNothing()
{
    Document document;

    auto id0 = document.addItem(new RectangleItem);
    auto id1 = document.addItem(new RectangleItem);
    auto id2 = document.addItem(new RectangleItem);
    auto id3 = document.addItem(new RectangleItem);
    auto id4 = document.addItem(new RectangleItem);

    StackOrderCommand command;
    command.setStackOperation(StackDown);
    command.setItem(id2);
    command.setReferenceItem(id2);
    command.setDocument(&document);

    command.redo();
    QCOMPARE(document.itemStack(), QList<quint64>() << id0 << id1 << id2 << id3 << id4);

    command.undo();
    QCOMPARE(document.itemStack(), QList<quint64>() << id0 << id1 << id2 << id3 << id4);
}

void tst_Document::stackDownWorks()
{
    Document document;

    auto id0 = document.addItem(new RectangleItem);
    auto id1 = document.addItem(new RectangleItem);
    auto id2 = document.addItem(new RectangleItem);
    auto id3 = document.addItem(new RectangleItem);
    auto id4 = document.addItem(new RectangleItem);

    StackOrderCommand command;
    command.setStackOperation(StackDown);
    command.setItem(id3);
    command.setReferenceItem(id1);
    command.setDocument(&document);

    command.redo();
    QCOMPARE(document.itemStack(), QList<quint64>() << id0 << id3 << id1 << id2 << id4);

    command.undo();
    QCOMPARE(document.itemStack(), QList<quint64>() << id0 << id1 << id2 << id3 << id4);
}

QTEST_MAIN(tst_Document)

#include "tst_document.moc"
